﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Cemit.NetFramework
{
    public class NetInput
    {
        public Vector2 MousePoint { get => _MousePoint; }

        const char MouseDataSprit = '_';

        InputSet<KeyCode> m_KeySets = new InputSet<KeyCode>();

        Vector2 _MousePoint;

        class InputSet<T>
        {
            public HashSet<T> enableSet = new HashSet<T>();
            public HashSet<T> downSet = new HashSet<T>();
            public HashSet<T> upSet = new HashSet<T>();
        }

        public NetInput(string playerId)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                Debug.LogError("要监视的玩家ID不能为空！");
                return;
            }

            //设置按键状态变化时的监听
            FrameSyncManager.AddOperationListener(OperationPrefix.KeyInput, playerId, OnKeyInput);

            //设置鼠标状态变化时的监听
            FrameSyncManager.AddOperationListener(OperationPrefix.MousePointSync, playerId, OnMouseInput);
        }

        private void OnMouseInput(string operation)
        {
            string[] pointData = operation.Split(MouseDataSprit);
            //分割后不足两部分视为无效数据
            if (pointData.Length != 2)
            {
                return;
            }

            if (!float.TryParse(pointData[0], out float x))
            {
                return;
            }

            if (!float.TryParse(pointData[1], out float y))
            {
                return;
            }

            _MousePoint.Set(x, y);
        }

        private void OnKeyInput(string operation)
        {
            //最后一位为+则表示按键松开，为-则表示按键按下
            InputState inputState = GetInputState(operation[operation.Length - 1]);
            KeyCode key = GetKeyCode(operation);

            SetInput(m_KeySets, key, inputState);
        }

        private static KeyCode GetKeyCode(string operation)
        {
            return (KeyCode)int.Parse(operation.Substring(0, operation.Length - 1));
        }

        private static InputState GetInputState(char state)
        {
            InputState inputState;
            switch (state)
            {
                case '+':
                    inputState = InputState.up;
                    break;
                case '-':
                    inputState = InputState.down;
                    break;
                default:
                    inputState = InputState.error;
                    break;
            }

            return inputState;
        }

        /// <summary>
        /// 设置按键状态
        /// </summary>
        private static void SetInput<T>(InputSet<T> set, T key, InputState state)
        {
            switch (state)
            {
                //按键抬起
                case InputState.up:
                    //if (!set.enableSet.Contains(key))
                    //{
                    //    Debug.LogWarning(
                    //        $"在没有收到{key}键按下的消息情况下收到了{key}键抬起的请求。");
                    //    return;
                    //}

                    FrameSyncManager.InvokeAtFrameUpdate(() => 
                    {
                        set.enableSet.Remove(key);
                        set.upSet.Add(key);
                    });

                    FrameSyncManager.InvokeAtNextFrameUpdate(() => 
                    {
                        set.upSet.Remove(key);
                    });

                    break;

                //按键按下
                case InputState.down:

                    FrameSyncManager.InvokeAtFrameUpdate(() =>
                    {
                        set.enableSet.Add(key);
                        set.downSet.Add(key);
                    });

                    FrameSyncManager.InvokeAtNextFrameUpdate(() =>
                    {
                        set.downSet.Remove(key);
                    });
                    
                    break;
            }
        }

        public static void SendMousePointToServer(Vector2 vector2)
        {
            FrameSyncManager.SendOperation(OperationPrefix.MousePointSync, $"{vector2.x}{MouseDataSprit}{vector2.y}");
        }

        public static void SendKeyToServer(KeyCode keyCode, InputState inputState)
        {
            char state;

            switch (inputState)
            {
                case InputState.up:
                    state = '+';
                    break;
                case InputState.down:
                    state = '-';
                    break;
                case InputState.error:
                    return;
                default:
                    return;
            }

            FrameSyncManager.SendOperation(OperationPrefix.KeyInput, $"{(int)keyCode}{state}");
        }

        public bool GetKey(KeyCode keyCode)
        {
            return m_KeySets.enableSet.Contains(keyCode);
        }

        public bool GetKeyDown(KeyCode keyCode)
        {
            return m_KeySets.downSet.Contains(keyCode);
        }

        public bool GetKeyUp(KeyCode keyCode)
        {
            return m_KeySets.upSet.Contains(keyCode);
        }
    }
}